///////////////////////////////////////////////////////////////////////////////
//	FILENAME:	eTAudioUI.m 
//	SUMMARY:	User Interface for Audio annotations to eText documents
//	SUPERCLASS:	eTAudioUI:eTImageUI:Object
//	INTERFACE:	None
//	PROTOCOLS:	<Inspectable>
//	AUTHOR:		Rohit Khare
//	COPYRIGHT:	(c) 1994 California Institure of Technology, eText Project
///////////////////////////////////////////////////////////////////////////////
//	IMPLEMENTATION COMMENTS
//		watch for hacks vis a vis sound display, play loops, and meters.
///////////////////////////////////////////////////////////////////////////////
//	HISTORY
//	07/24/94:	Rearchitected for PR1/eTImage
//	01/24/94:	Created. Derived largely from Version3's temporary Hypertext
//				'93 hack. Renamed as eTAudio and aTAudioUI.
///////////////////////////////////////////////////////////////////////////////

#import "eTAudioUI.h"

@implementation eTAudioUI
//    id	audioPanel;
//    id	audioView;
//    id	etAudio;
//    id	nameField;
//    id	eraseButton;
//    id	pauseButton;
//    id	playButton;
//    id	recordButton;
//    id	stopButton;
//    id	soundMeter;
//    id	soundView;

- setAnnotation:newAudio
{	
	id theSound;
	
	if (etAudio == newAudio) return self;
	[super setAnnotation:newAudio];	// this is an awkward naming of the "chain" 

	// properly unload the old audio
	[soundMeter stop:self];
	[soundMeter setSound:nil];
	[soundView stop:self];
	[[soundView sound] setDelegate:nil];
	if ([etAudio respondsTo:@selector(audioEnded)])
		[etAudio audioEnded];
	
	etAudio = newAudio;
	[nameField setStringValue:[etAudio audioName]];
	[playButton setState:0];
	[pauseButton setState:0];
	[stopButton setState:0];
	[recordButton setState:0];
	theSound = [etAudio sound];
	[soundView setSound:theSound];
	[theSound setDelegate:self];
	[soundView setDelegate:self];		// redundant, but hey...
	[soundMeter setSound:theSound];
//	There ought to be a link switch somewhere on that damn panel...
//	[linkSwitch setState:[etAudio isAudioLinked];
	return self;
}

- soundView {return soundView;}
- soundMeter {return soundMeter;}
///////////////////////////////////
+ new
{
	static eTAudioUI *ui = nil;
	
	if (!ui) {
		ui = [[eTAudioUI alloc] init];
	}
	return ui;
}
- init
{
	char        buf[MAXPATHLEN];
	NXBundle   *bundle;

	[super init];
	bundle = [NXBundle bundleForClass:[self class]];
	if ( [bundle getPath:buf forResource:"eTAudioUI" ofType:"nib"] ) {
		[NXApp loadNibFile:buf owner:self withNames:NO];
	} else {
		NXLogError("NIB not found: eTAudioUI");
	}
	audioView = [audioPanel contentView];
	return self;
}
- free {return self;}

///////////////////////////////////
#define PROP "Audio Properties"
- (const NXAtom *) types
{
	static NXAtom *types = NULL;
	
	if (!types) {
		int i;
		const NXAtom *superTypes = [super types];
		
		for(i=0;superTypes[i];i++);
		i++; // make room for terminating NULL
		i++; // make room for our type
		types = malloc(i * sizeof(NXAtom));
		types[0] = NXUniqueString(PROP);
		for(i=0;superTypes[i];i++) types[i+1] = superTypes[i];
		types[i+1] = NULL;
	}
	return types;
}
- (const char *) inspectorTitle
{
	return NXUniqueString("Audio");
}
- resignInspector: (View *) oldInspector ofType: (const char *) type
{
	if (oldInspector == audioView) {
		[soundMeter stop:self];
		[soundView resignFirstResponder];
		[audioView removeFromSuperview];	// keep it attached to some window
		[audioPanel setContentView:audioView];
	} else 
		[super resignInspector:oldInspector ofType:type];
	return self;
}
- activateInspector: (View *) newInspector ofType: (const char *) type
{
	if (newInspector == audioView) {
		//anything special here?
		switch ([[soundView soundBeingProcessed] status]) {
			case NX_SoundPlayingPaused:
			case NX_SoundRecordingPaused:
			case NX_SoundPlaying:
			case NX_SoundRecording:			[soundMeter run:self]; break;
		}
		[soundView setEditable:[etAudio isAudioMutable]];
		[nameField setEditable:[etAudio isAudioMutable]];
	} else 
		[super activateInspector:newInspector ofType:type];
	return self;
}
- inspectorForType:(const char *) type
{
	if(!strcmp(type,NXUniqueString(PROP)))
		return audioView;
	return [super inspectorForType:type];
}

///////////////////////////////////
- editName:sender
{
	[etAudio setAudioName:[sender stringValue]];
	return self;
}

- erase:sender
{
	if (![etAudio isAudioMutable]) {
		NXRunAlertPanel( "eTAudio",
		"You cannot modify the sound file %s. Try copying it "
		"directly if you need to edit it.", NULL, NULL, NULL,
		[etAudio audioName]);
		return self;
	}
	[soundView stop:self];
	[soundMeter stop:self];
	if ([etAudio respondsTo:@selector(audioEnded)])
		[etAudio audioEnded];
	[soundView setSelection:0 size:[[etAudio sound] sampleCount]];
	[soundView delete:self];
	[playButton setState:0];
	[recordButton setState:0];
	[pauseButton setState:0];
	[[audioView window] display];
    return self;
}

- pause:sender
{
 	switch ([[soundView soundBeingProcessed] status]) {
		case NX_SoundPlaying:
		case NX_SoundRecording:			
			[soundView pause:self]; 
			if ([etAudio respondsTo:@selector(audioPaused)])
				[etAudio audioPaused];
			break;
		case NX_SoundPlayingPaused:
		case NX_SoundRecordingPaused:
			[soundView resume:self]; 
			if ([etAudio respondsTo:@selector(audioResumed)])
				[etAudio audioResumed];
			break;
		default:						[pauseButton setState:0];
	}
    return self;
}

- play:sender
{
	if ([[soundView soundBeingProcessed] status] == NX_SoundPlaying) {
		[self stop:sender];
		return self;
	}
	if( [[soundView soundBeingProcessed] duration]== 0.0) {
		[playButton setState:0];
		if ([etAudio respondsTo:@selector(audioEnded)])
			[etAudio audioEnded];
		return self;
	}
	[recordButton setState:0];
	[pauseButton setState:0];
	[soundView play:self];
	[soundMeter setSound:[soundView soundBeingProcessed]];
	if ([soundMeter window]) [soundMeter run:self];
	if ([etAudio respondsTo:@selector(audioStarted)])
		[etAudio audioStarted];
	return self;
}

- record:sender
{
	if (![etAudio isAudioMutable]) {
		NXRunAlertPanel( "eTAudio",
		"You cannot modify the sound file %s. Try copying "
		"it directly if you need to edit it.", NULL, NULL, NULL,
		[etAudio audioName]);
		[recordButton setState:0];
		if ([etAudio respondsTo:@selector(audioEnded)])
			[etAudio audioEnded];
		return nil;
	}
	if ([[soundView soundBeingProcessed] status] == NX_SoundRecording) {
		[self stop:sender];
		return self;
	}
	[playButton setState:0];
	[pauseButton setState:0];
	[soundView record:self];
	[soundMeter setSound:[soundView soundBeingProcessed]];
	[soundMeter run:self];
	if ([etAudio respondsTo:@selector(audioStarted)])
		[etAudio audioStarted];
    return self;
}

- stop:sender
{
	[playButton setState:0];
	[recordButton setState:0];
	[pauseButton setState:0];
	[soundView stop:self];
	[audioView display];
	[soundMeter stop:self];
	if ([etAudio respondsTo:@selector(audioEnded)])
		[etAudio audioEnded];
	return self;
}
- didPlay:sender {
	[soundMeter stop:self];
	[playButton setState:0];
	[recordButton setState:0];
	[pauseButton setState:0];
	[[audioView window] display];
	if ([etAudio respondsTo:@selector(audioEnded)])
		[etAudio audioEnded];
	return self;
}
- didRecord:sender {
	[soundMeter stop:self];
	[playButton setState:0];
	[recordButton setState:0];
	[pauseButton setState:0];
	if ([etAudio respondsTo:@selector(audioEnded)])
		[etAudio audioEnded];
	return self;
}
- hadError:sender {return [stopButton performClick:self];}
- soundDidChange:sender {return [[etAudio etDoc] touch];}
/////////////////////////////////
- click:sender
{
	if (sender != etAudio) return nil;
	if (![soundView soundBeingProcessed])
		[soundView setSound:[etAudio sound]];
	switch ([soundView soundBeingProcessed] ?
			[[soundView soundBeingProcessed] status] :
			[[soundView sound] status]) {
		case NX_SoundStopped:		[playButton performClick:sender]; break;
		case NX_SoundPlayingPaused:
		case NX_SoundRecordingPaused:
		case NX_SoundPlaying:
		case NX_SoundRecording:		[pauseButton performClick:sender]; break;
	}
	return self;
}

- doubleClick:sender 
{
	if (sender != etAudio) return nil;
	return [stopButton performClick:self];
}
@end
@interface eTSoundMeter:SoundMeter
{}
- drawCurrentValue;
@end
@implementation eTSoundMeter
- drawCurrentValue{if (window) return [super drawCurrentValue]; return self;}
@end
